package org.bjf.modules.user.service;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.bjf.modules.user.bean.User;
import org.bjf.utils.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.ZSetOperations.TypedTuple;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * redis 排行榜
 *
 * @author bjf
 * @date 2017/11/27
 */
@Service
@Slf4j
public class RankService {

    @Resource
    private RedisUtil redis;
    @Resource
    private UserService userService;

    /**
     * 新增榜单分数
     *
     * @param rankKey 排行榜key
     * @param userId  用户ID
     * @param score   分数
     */
    public void addScore(String rankKey, Long userId, double score) {
        // 与榜单旧分数对比，高于才更新
        Double oldScore = redis.zScore(rankKey, userId);
        if (oldScore == null || oldScore < score) {
            redis.zAdd(rankKey, userId.toString(), score);
        }
    }

    /**
     * 查询用户排名
     *
     * @param rankKey 排行榜key
     * @param userId  用户ID
     */
    public RankInfo getUserRank(String rankKey, long userId) {
        //===1.查询用户自己排名
        User user = userService.get(userId);
        RankInfo rankInfo = new RankInfo();
        BeanUtils.copyProperties(user, rankInfo);
        Double score = redis.zScore(rankKey, userId);
        if (score == null) {
            rankInfo.setScore(0D);
            //-1表示无排名
            rankInfo.setRanking(-1L);
        } else {
            Long ranking = redis.zReverseRank(rankKey, userId);
            rankInfo.setRanking(ranking + 1);
            rankInfo.setScore(score);
        }

        return rankInfo;
    }


    /**
     * 榜单列表
     *
     * @param rankKey 排行榜key
     */
    public List<RankInfo> listRankPage(String rankKey, long page, long pageSize) {

        //===1.分页查出redis榜单
        Set<TypedTuple<String>> tuples = redis
                .zReverseRangeWithScores(rankKey, (page - 1) * pageSize, page * pageSize);

        //===2.查询用户信息
        List<Long> uIds = tuples.stream()
                .map(e -> Long.valueOf(Objects.requireNonNull(e.getValue()).toString()))
                .collect(Collectors.toList());
        Map<Long, User> userMap = userService.mapByIds(uIds, Long.class);

        //===3.返回rankList
        List<RankInfo> rankUsers = new ArrayList<>(tuples.size());
        for (TypedTuple<String> tuple : tuples) {
            User user = userMap.get(Long.valueOf(tuple.getValue()));
            if (user == null) {
                continue;
            }
            RankInfo rank = new RankInfo();
            BeanUtils.copyProperties(user, rank);
            rank.setScore(tuple.getScore());
            rank.setRanking(redis.zReverseRank(rankKey, tuple.getValue()) + 1L);
            rankUsers.add(rank);
        }
        return rankUsers;
    }


    @Data
    public static class RankInfo {

        private Long userId;
        /**
         * 分数
         */
        private Double score;
        /**
         * 排名
         */
        private Long ranking;
        /**
         * 昵称
         */
        private String nickName;
        /**
         * 用户头像
         */

        private String headImg;
    }


}
